Skip to content

Add a bunch of stuffs to Index.Remove() #398

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
Closed

Add a bunch of stuffs to Index.Remove() #398

wants to merge 11 commits into from

Conversation

yorah
Copy link
Contributor

@yorah yorah commented Apr 18, 2013

With this PR, it is now possible to:

  • Pass ExplicitPathsOptions to Index.Remove()
  • Remove whole folders from the index
  • Remove files/folders from the index without removing them from the workdir (git rm --cached)
  • Clear conflicts state when removing entries from the index

This fixes #270 and #327.

Please note that the behavior is now consistent with Index.Stage()/Unstage():

  • passing pathspecs which don't match any files does not throw anymore.
  • passing explicit paths (by passing a non-null ExplicitPathsOptions) which don't match any files will throw.

This is a breaking change.

@ethomson
Copy link
Member

I'm strongly in favor of changing the remove semantics to allow for rm --cached.

In doing this, we should probably start calling git_index_remove_bypath() so that conflicts are handled properly.

@@ -194,6 +194,50 @@ private static void InvalidMoveUseCases(string sourcePath, FileStatus sourceStat
}
}

public void CanRemoveAFolderThroughUsageOfPathspecs()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't we missing a [Fact] attribute here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a matter of fact, yes we do!

@nulltoken
Copy link
Member

@yishaigalatzer @anaisamp This PR should fix some of your requests.

}

[Fact]
public void RemovingAInvalidFileThrows()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we now have only one case, could you please update the name of the test to actually express what kind of state is being invalid?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we now have only one case

Or maybe are we missing some of them. What about FileStatus.TypeChanged for instance?

@anaisamp
Copy link

Thank you so much! Good job, you guys are awesome! :)

@yorah
Copy link
Contributor Author

yorah commented Apr 19, 2013

Here is an update:

  • Added lots of tests to cover git rm --cached
  • Tweaked Index.Remove() to allow for git rm --cached
  • Used git_index_remove_bypath in internal implementation

Missing:

  • Handling of git rm -f
  • Handling of TypeChanged records. There seems to be deeper things missing to allow for it at the moment (RetrieveStatus should be able to report it for example)
  • Tests to show what git_index_remove_bypath allows us to do now (@ethomson do you have ideas for that by any chance?)

@nulltoken would it be possible to address the first 2 points in another PR?

@nulltoken
Copy link
Member

@nulltoken would it be possible to address the first 2 points in another PR?

Cool with me 👍
Will you work on them once this one is merged or should we create an issue to track those tasks?

Used git_index_remove_bypath in internal implementation

@yishaigalatzer I believe this should fix #325 as well.

@yorah
Copy link
Contributor Author

yorah commented Apr 20, 2013

Will you work on them once this one is merged or should we create an issue to track those tasks?

I will work on the git rm -f once this one is merged. For the TypeChanged one, I will open an issue to get some feedback first (about the best way tp add it). I have the feeling it may be more complex than it seems.

@yorah
Copy link
Contributor Author

yorah commented Apr 22, 2013

In the Index.Remove(), I throw a bunch of LibGit2SharpException. Would it be better to throw a strongly-typed exception, and if yes, how would you call it?

/cc @dahlbyk @haacked @carlosmn

}

if (dic.Count == 0)
foreach (string path in pathsList.Where(p => Directory.Exists(Path.Combine(wd, p))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly a premature optimization, but checking Directory.Exists() twice for every entry in pathsList seems like it's worth avoiding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed!

@dahlbyk
Copy link
Member

dahlbyk commented Apr 22, 2013

In the Index.Remove(), I throw a bunch of LibGit2SharpException. Would it be better to throw a strongly-typed exception, and if yes, how would you call it?

👍

RemoveFromIndexException?

yorah added 11 commits April 23, 2013 11:00
Note: it means that the paths passed to Remove() are pathspecs, and thus behavior has been aligned with Stage()/Unstage() => calling Remove() by passing a pathspec which doesn't match any paths doesn't throw anymore (breaking change).
This makes the behavior fully consistent with Index.Stage()/Unstage().
Lots of test cases added, to mimic git rm --cached behavior.
Beware, this is supported only for files which exist in the workdir (cf. comment in code).
Partially fixes #325
@yorah
Copy link
Contributor Author

yorah commented Apr 23, 2013

RemoveFromIndexException?

❤️

@yorah
Copy link
Contributor Author

yorah commented Apr 23, 2013

Ok, time to look back at what we do in this PR.

There is one corner-case with the current approach: as we rely on Diff (for pathspecs expansion at least), and as libgit2's git_iterator_for_index() seem to only carea bout entries in stage level 0, it means that for merge conflicts (with stage level = 1, 2 or 3), we don't detect index entries if there is no corresponding file in the workdir. This limit is expressed in the last commit (@39f8947)

Note: with a RetrieveStatus approach, other problems would arise (we would need pathspecs parsing in lg2s, the ability to easily retrieve IndexEntries with StageLevel != 0, and some way to get meaningful merge statuses), linked to already existing issues: #279, #271

Another option would be to consider that this whole logic should be part of libgit2, but I'm afraid this might be considered a bit too high-level. @carlosmn Thoughts?

All in all, I think I would advocate merging this PR as is, and build from there. I think the tests are quite clear and express clearly the expectations, so should we refactor we have our bases covered.

@ethomson
Copy link
Member

Does this mean that I can't call Remove() on a file that doesn't exist in the workdir but does have high-stage index entries?

I'm not sure that's such a corner case, actually; I added git_index_remove_bypath in the first place so that we could clear conflict entries when we wanted to "take" the delete side of an edit/delete conflict.

So having this would be very beneficial for us - it would be one less hack to drag forward.

I think that a flag to the index iterator to include high-stage entries may not be inappropriate if that would be helpful?

@yorah
Copy link
Contributor Author

yorah commented Apr 23, 2013

Does this mean that I can't call Remove() on a file that doesn't exist in the workdir but does have high-stage index entries?

Yes 😞

I'm not sure that's such a corner case, actually; I added git_index_remove_bypath in the first place so that we could clear conflict entries when we wanted to "take" the delete side of an edit/delete conflict.

Well, at the moment you can still do it, just not when the file is missing from the workdir.

I think that a flag to the index iterator to include high-stage entries may not be inappropriate if that would be helpful?

I'm afraid this won't be enough. From what I understand so far, the semantics returned by git diff when showing a merge is not the same as the "standard" format (look at the -cc option). Maybe someone from libgit2 could jump in at this point?

Edit (proposal): what about letting the repo.Index namespace handle only the stage level 0 (ie: it means going back to calling git_index_remove(), and add a repo.Conflicts.RemoveFile(string relativePath) which would call git_index_remove_bypath() ? The idea I'm trying to play with is to move all the things related to stage level 1, 2 and 3 in the repo.Conflicts namespace.

@ethomson
Copy link
Member

I'm afraid this won't be enough. From what I understand so far, the semantics returned by git diff when showing a merge is not the same as the "standard" format (look at the -cc option). Maybe someone from libgit2 could jump in at this point?

What can libgit2 do differently to enhance this scenario?

Edit (proposal): what about letting the repo.Index namespace handle only the stage level 0 (ie: it means going back to calling git_index_remove(), and add a repo.Conflicts.RemoveFile(string relativePath) which would call git_index_remove_bypath() ? The idea I'm trying to play with is to move all the things related to stage level 1, 2 and 3 in the repo.Conflicts namespace.

I don't think you should go back to git_index_remove here; remove_bypath is a very simple and very safe wrapper around remove that moves conflicts to the REUC. Unless you can think of an explicit case where you do not want to move conflicts to the REUC but aren't working on index entries at a lower level, then it should probably be preferred to avoid confusion.

I'm okay with an explicit Conflicts.Remove(...) that calls git_index_remove_bypath -- this is basically what we're doing now -- but I was really hopeful that we could have a single call to remove index entries instead of having to know whether the file was on-disk or not, etc, etc.

@yorah
Copy link
Contributor Author

yorah commented Apr 24, 2013

What can libgit2 do differently to enhance this scenario?

It would be nice to have libgit2 able to report conflicts in git_status_foreach_ext(). I think this discussion has already been initiated/envisioned by @arrbee in #271.

@nulltoken
Copy link
Member

Unless someone strongly opposes, I'm going to merge this as is later today.

@yorah Could you please create an issue so we that we track this?

/* Conflicts clearing through Index.Remove() only works when a version of the entry exists in the workdir.
 * This is because libgit2's git_iterator_for_index() seem to only care about stage level 0.
 * Corrolary: other cases only work out of sheer luck (however, the behaviour is stable, so I guess we
 *   can rely on it for the moment.
 * [InlineData(true, "ancestor-only.txt", false, false, FileStatus.Nonexistent, 0)]
 * [InlineData(false, "ancestor-only.txt", false, false, FileStatus.Nonexistent, 0)]
 */

@yorah yorah mentioned this pull request Apr 24, 2013
3 tasks
@yorah
Copy link
Contributor Author

yorah commented Apr 24, 2013

@yorah Could you please create an issue so we that we track this?

#411

@nulltoken
Copy link
Member

@yorah Could you please create an issue so we that we track this?

#411

🎱

@nulltoken
Copy link
Member

AMAZING work!

Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants